package driver

import (
	"errors"
	"log/slog"
	"strconv"

	"gitee.com/gousing/cache/internal"
	"gitee.com/gousing/cache/storage"
)

// ---------------------------------------
// RedisCache 简单集合实现
// SString String 字符串集合
// SInt    Int64 数值集合
// ---------------------------------------

// SStringAdd 向指定 key 的 String 集合添加一个或多个成员元素
//   - 如果指定 key 的集合不存在, 则新建集合并添加值到集合
//   - 如果指定 key 不是一个 String 集合, 则返回错误
//   - 如果指定 key 的集合存在, 则添加值到集合
//   - 如果 items为空, 则什么也不做, 直接返回nil
func (c *RedisCache) SStringAdd(key string, items ...string) error {
	if key == "" {
		return storage.ErrKeyIsEmpty
	}
	if len(items) == 0 {
		return nil
	}

	// 单个实例锁, 限制单个实例(主线程)应用内的并发执行
	if c.selfLocked {
		sLock := c.getSelfLock(key)
		sLock.Lock()
		defer sLock.Unlock()
	}

	// 通过 RedisLock 分布式锁限制其他实例线程(客户端)并发执行同一键的重复查询
	rLock := c.redisLock.NewDefault(key)
	if err := rLock.TryLock(); err != nil {
		internal.GetLogger().Error("cache: SStringAdd TryLock error", slog.String("key", key), slog.Any("err", err))
		return err
	}
	defer func() {
		if err := rLock.UnlockAndPutPool(); err != nil {
			internal.GetLogger().Error("cache: SStringAdd Unlock error", slog.String("key", key), slog.Any("err", err))
		}
	}()

	kind, err := c.keyKinds.Get(key)
	if err != nil {
		if err == storage.ErrKeyNotExists || err == storage.ErrKeyExpired {
			// 缓存不存在或过期: 新建指定键名的集合并添加值到集合
			// 先记录键的类型为 String 集合类型, 并设置过期时间(0表示永久不过期)
			err = c.keyKinds.Set(key, storage.KindSetString, 0)
			if err != nil {
				return err
			}
			if len(items) == 1 {
				err = c.client.SAdd(c.ctx, key, items[0]).Err()
			} else {
				data := make([]any, 0, len(items))
				for _, item := range items {
					data = append(data, item)
				}
				err = c.client.SAdd(c.ctx, key, data...).Err()
			}
			return err
		}
		return err
	}
	if kind != storage.KindSetString {
		return storage.ErrValueNotSetString
	}

	// 集合存在: 则添加值到集合
	if len(items) == 1 {
		err = c.client.SAdd(c.ctx, key, items[0]).Err()
	} else {
		data := make([]any, 0, len(items))
		for _, item := range items {
			data = append(data, item)
		}
		err = c.client.SAdd(c.ctx, key, data...).Err()
	}
	return err
}

// SStringRemove 从指定 key 的 String 集合中移除一个或多个成员
//   - 如果指定 key 的集合不存或不是一个 String 集合, 则返回错误
//   - 如果items为空, 则什么也不做, 直接返回nil
func (c *RedisCache) SStringRemove(key string, items ...string) error {
	if key == "" {
		return storage.ErrKeyIsEmpty
	}
	if len(items) == 0 {
		return nil
	}
	kind, err := c.keyKinds.Get(key)
	if err != nil {
		if err == storage.ErrKeyNotExists || err == storage.ErrKeyExpired {
			return storage.ErrKeyNotExists
		}
		return err
	}
	if kind != storage.KindSetString {
		return storage.ErrValueNotSetString
	}
	// 单个实例锁, 限制单个实例(主线程)应用内的并发执行
	if c.selfLocked {
		sLock := c.getSelfLock(key)
		sLock.Lock()
		defer sLock.Unlock()
	}

	// 通过 RedisLock 分布式锁限制其他实例线程(客户端)并发执行同一键的重复查询
	rLock := c.redisLock.NewDefault(key)
	if err := rLock.TryLock(); err != nil {
		internal.GetLogger().Error("cache: SStringRemove TryLock error", slog.String("key", key), slog.Any("err", err))
		return err
	}
	defer func() {
		if err := rLock.UnlockAndPutPool(); err != nil {
			internal.GetLogger().Error("cache: SStringRemove Unlock error", slog.String("key", key), slog.Any("err", err))
		}
	}()

	// 集合存在: 则删除元素
	if len(items) == 1 {
		err = c.client.SRem(c.ctx, key, items[0]).Err()
	} else {
		data := make([]any, 0, len(items))
		for _, item := range items {
			data = append(data, item)
		}
		err = c.client.SRem(c.ctx, key, data...).Err()
	}
	return err
}

// SStringClear 清空指定 key 的 String 集合
//   - 如果指定 key 的集合不存或不是一个 String 集合, 则返回错误
func (c *RedisCache) SStringClear(key string) error {
	if key == "" {
		return storage.ErrKeyIsEmpty
	}
	kind, err := c.keyKinds.Get(key)
	if err != nil {
		if err == storage.ErrKeyNotExists || err == storage.ErrKeyExpired {
			return storage.ErrKeyNotExists
		}
		return err
	}
	if kind != storage.KindSetString {
		return storage.ErrValueNotSetString
	}
	// 单个实例锁, 限制单个实例(主线程)应用内的并发执行
	if c.selfLocked {
		sLock := c.getSelfLock(key)
		sLock.Lock()
		defer sLock.Unlock()
	}

	// 通过 RedisLock 分布式锁限制其他实例线程(客户端)并发执行同一键的重复查询
	rLock := c.redisLock.NewDefault(key)
	if err := rLock.TryLock(); err != nil {
		internal.GetLogger().Error("cache: SStringClear TryLock error", slog.String("key", key), slog.Any("err", err))
		return err
	}
	defer func() {
		if err := rLock.UnlockAndPutPool(); err != nil {
			internal.GetLogger().Error("cache: SStringClear Unlock error", slog.String("key", key), slog.Any("err", err))
		}
	}()

	// 清空集合
	return c.client.Del(c.ctx, key).Err()
}

// SStringContains 判断一个或多个成员是否全部在指定 key 的 String 集合中
//   - 如果指定 key 的集合不存或不是一个 String 集合, 则返回 false
//   - 查询多个成员, 任意一个成员不在集合中, 则返回 false
func (c *RedisCache) SStringContains(key string, items ...string) bool {
	if key == "" {
		return false
	}
	if len(items) == 0 {
		return false
	}
	kind, err := c.keyKinds.Get(key)
	if err != nil || kind != storage.KindSetString {
		return false
	}
	// 单个实例锁, 限制单个实例(主线程)应用内的并发执行
	if c.selfLocked {
		sLock := c.getSelfLock(key)
		sLock.Lock()
		defer sLock.Unlock()
	}

	// 通过 RedisLock 分布式锁限制其他实例线程(客户端)并发执行同一键的重复查询
	rLock := c.redisLock.NewDefault(key)
	if err := rLock.TryLock(); err != nil {
		internal.GetLogger().Error("cache: SStringContains TryLock error", slog.String("key", key), slog.Any("err", err))
		return false
	}
	defer func() {
		if err := rLock.UnlockAndPutPool(); err != nil {
			internal.GetLogger().Error("cache: SStringContains Unlock error", slog.String("key", key), slog.Any("err", err))
		}
	}()

	// 集合存在: 判断一个或多个成员是否在字符串集合中
	if len(items) == 1 {
		return c.client.SIsMember(c.ctx, key, items[0]).Val()
	}

	// 集合存在: 判断一个或多个成员是否在字符串集合中
	// > 6.2.0 版本后才支持 SMISMEMBER 批量判断成员是否在集合中
	if c.RedisVerGreaterEqual(6, 2) {
		data := make([]any, 0, len(items))
		for _, item := range items {
			data = append(data, item)
		}
		res := c.client.SMIsMember(c.ctx, key, data...).Val()
		for _, ok := range res {
			// 任意一个成员不在集合中, 则返回 false
			if !ok {
				return false
			}
		}
		return true
	}
	// 低版本不支持批量判断成员是否在集合中, 则逐个查询
	for _, item := range items {
		// 任意一个成员不在集合中, 则返回 false
		if !c.client.SIsMember(c.ctx, key, item).Val() {
			return false
		}
	}
	return true
}

// SStringContainsSome 判断一个或多个成员的中任意一个成员是否在指定 key 的 String 集合中
//   - 如果指定 key 的集合不存或不是一个 String 集合, 则返回 false
//   - 查询多个成员, 任意一个成员存在集合中, 则返回 true
func (c *RedisCache) SStringContainsSome(key string, items ...string) bool {
	if key == "" {
		return false
	}
	if len(items) == 0 {
		return false
	}
	kind, err := c.keyKinds.Get(key)
	if err != nil || kind != storage.KindSetString {
		return false
	}

	// 单个实例锁, 限制单个实例(主线程)应用内的并发执行
	if c.selfLocked {
		sLock := c.getSelfLock(key)
		sLock.Lock()
		defer sLock.Unlock()
	}

	// 通过 RedisLock 分布式锁限制其他实例线程(客户端)并发执行同一键的重复查询
	rLock := c.redisLock.NewDefault(key)
	if err := rLock.TryLock(); err != nil {
		internal.GetLogger().Error("cache: SStringContainsSome TryLock error", slog.String("key", key), slog.Any("err", err))
		return false
	}
	defer func() {
		if err := rLock.UnlockAndPutPool(); err != nil {
			internal.GetLogger().Error("cache: SStringContainsSome Unlock error", slog.String("key", key), slog.Any("err", err))
		}
	}()

	// 集合存在: 判断一个或多个成员是否在字符串集合中
	if len(items) == 1 {
		return c.client.SIsMember(c.ctx, key, items[0]).Val()
	}
	// 集合存在: 判断一个或多个成员是否在字符串集合中
	// > 6.2.0 版本后才支持 SMISMEMBER 批量判断成员是否在集合中
	if c.RedisVerGreaterEqual(6, 2) {
		data := make([]any, 0, len(items))
		for _, item := range items {
			data = append(data, item)
		}
		res := c.client.SMIsMember(c.ctx, key, data...).Val()
		for _, ok := range res {
			// 任意一个成员存在集合中, 则返回 true
			if ok {
				return true
			}
		}
		return false
	}
	// 低版本不支持批量判断成员是否在集合中, 则逐个查询
	for _, item := range items {
		// 任意一个成员不在集合中, 则返回 false
		if c.client.SIsMember(c.ctx, key, item).Val() {
			// 任意一个成员存在集合中, 则返回 true
			return true
		}
	}
	return false
}

// SStringMembers 获取指定 key 的 String 集合的所有成员
//   - 如果指定 key 的集合不存或不是一个 String 集合, 则返回错误
func (c *RedisCache) SStringMembers(key string) ([]string, error) {
	if key == "" {
		return []string{}, storage.ErrKeyIsEmpty
	}
	kind, err := c.keyKinds.Get(key)
	if err != nil {
		if err == storage.ErrKeyNotExists || err == storage.ErrKeyExpired {
			return []string{}, storage.ErrKeyNotExists
		}
		return []string{}, err
	}
	if kind != storage.KindSetString {
		return []string{}, storage.ErrValueNotSetString
	}
	// 集合存在: 则返回所有成员
	return c.client.SMembers(c.ctx, key).Result()
}

// SStringTraverse 遍历指定 key 的 String 集合的所有成员
//   - 如果指定 key 的集合不存或不是一个 String 集合, 则返回错误
//   - fn 签名是 iter.Seq[string], 迭代过程中, 返回 false 则停止遍历
func (c *RedisCache) SStringTraverse(key string, fn func(string) bool) error {
	if key == "" {
		return storage.ErrKeyIsEmpty
	}
	kind, err := c.keyKinds.Get(key)
	if err != nil {
		if err == storage.ErrKeyNotExists || err == storage.ErrKeyExpired {
			return storage.ErrKeyNotExists
		}
		return err
	}
	if kind != storage.KindSetString {
		return storage.ErrValueNotSetString
	}
	// 注意: 这里不加单实例锁, 因为迭代过程中允许并发操作集合, 比如删除成员等操作
	// 集合存在: 则迭代所有成员
	var (
		cursor  uint64
		members []string
	)
	for {
		members, cursor, err = c.client.SScan(c.ctx, key, cursor, "*", 100).Result()
		if err != nil {
			return err
		}
		for _, item := range members {
			if !fn(item) {
				return nil
			}
		}
		// 如果游标值为 0，说明迭代结束
		if cursor == 0 {
			return nil
		}
	}
}

// SStringSize 获取指定 key 的 String 集合的成员数量
//   - 如果指定 key 的集合不存或不是一个 String 集合, 则返回错误
func (c *RedisCache) SStringSize(key string) (int64, error) {
	if key == "" {
		return 0, storage.ErrKeyIsEmpty
	}
	kind, err := c.keyKinds.Get(key)
	if err != nil {
		if err == storage.ErrKeyNotExists || err == storage.ErrKeyExpired {
			return 0, storage.ErrKeyNotExists
		}
		return 0, err
	}
	if kind != storage.KindSetString {
		return 0, storage.ErrValueNotSetString
	}
	// 集合存在: 则返回成员数量
	return c.client.SCard(c.ctx, key).Result()
}

// SIntAdd 向指定 key 的 Int64 集合添加一个或多个成员元素
//   - 如果指定 key 的集合不存在, 则新建集合并添加值到集合
//   - 如果指定 key 不是一个 Int64 集合, 则返回错误
//   - 如果指定 key 的集合存在, 则添加值到集合
//   - 如果 items 为空, 则什么也不做, 直接返回nil
func (c *RedisCache) SIntAdd(key string, items ...int64) error {
	if key == "" {
		return storage.ErrKeyIsEmpty
	}
	if len(items) == 0 {
		return nil
	}

	// 单个实例锁, 限制单个实例(主线程)应用内的并发执行
	if c.selfLocked {
		sLock := c.getSelfLock(key)
		sLock.Lock()
		defer sLock.Unlock()
	}

	// 通过 RedisLock 分布式锁限制其他实例线程(客户端)并发执行同一键的重复查询
	rLock := c.redisLock.NewDefault(key)
	if err := rLock.TryLock(); err != nil {
		internal.GetLogger().Error("cache: SIntAdd TryLock error", slog.String("key", key), slog.Any("err", err))
		return err
	}
	defer func() {
		if err := rLock.UnlockAndPutPool(); err != nil {
			internal.GetLogger().Error("cache: SIntAdd Unlock error", slog.String("key", key), slog.Any("err", err))
		}
	}()

	kind, err := c.keyKinds.Get(key)
	if err != nil {
		if err == storage.ErrKeyNotExists || err == storage.ErrKeyExpired {
			// 缓存不存在或过期: 新建指定键名的集合并添加值到集合
			// 先记录键的类型为 Int64 集合类型, 并设置过期时间(0表示永久不过期)
			err = c.keyKinds.Set(key, storage.KindSetInt, 0)
			if err != nil {
				return err
			}
			if len(items) == 1 {
				err = c.client.SAdd(c.ctx, key, strconv.FormatInt(items[0], 10)).Err()
			} else {
				data := make([]any, 0, len(items))
				for _, item := range items {
					data = append(data, strconv.FormatInt(item, 10))
				}
				err = c.client.SAdd(c.ctx, key, data...).Err()
			}
			return err
		}
		return err
	}
	if kind != storage.KindSetInt {
		return storage.ErrValueNotSetInt
	}

	// 集合存在: 则添加值到集合
	if len(items) == 1 {
		err = c.client.SAdd(c.ctx, key, strconv.FormatInt(items[0], 10)).Err()
	} else {
		data := make([]any, 0, len(items))
		for _, item := range items {
			data = append(data, strconv.FormatInt(item, 10))
		}
		err = c.client.SAdd(c.ctx, key, data...).Err()
	}
	return err
}

// SIntRemove 从指定 key 的 Int64 集合中移除一个或多个成员
//   - 如果指定 key 的集合不存或不是一个 Int64 集合, 则返回错误
//   - 如果items为空, 则什么也不做, 直接返回nil
func (c *RedisCache) SIntRemove(key string, items ...int64) error {
	if key == "" {
		return storage.ErrKeyIsEmpty
	}
	if len(items) == 0 {
		return nil
	}
	kind, err := c.keyKinds.Get(key)
	if err != nil {
		if err == storage.ErrKeyNotExists || err == storage.ErrKeyExpired {
			return storage.ErrKeyNotExists
		}
		return err
	}
	if kind != storage.KindSetInt {
		return storage.ErrValueNotSetInt
	}
	// 单个实例锁, 限制单个实例(主线程)应用内的并发执行
	if c.selfLocked {
		sLock := c.getSelfLock(key)
		sLock.Lock()
		defer sLock.Unlock()
	}

	// 通过 RedisLock 分布式锁限制其他实例线程(客户端)并发执行同一键的重复查询
	rLock := c.redisLock.NewDefault(key)
	if err := rLock.TryLock(); err != nil {
		internal.GetLogger().Error("cache: SIntRemove TryLock error", slog.String("key", key), slog.Any("err", err))
		return err
	}
	defer func() {
		if err := rLock.UnlockAndPutPool(); err != nil {
			internal.GetLogger().Error("cache: SIntRemove Unlock error", slog.String("key", key), slog.Any("err", err))
		}
	}()

	// 集合存在: 则删除元素
	if len(items) == 1 {
		err = c.client.SRem(c.ctx, key, strconv.FormatInt(items[0], 10)).Err()
	} else {
		data := make([]any, 0, len(items))
		for _, item := range items {
			data = append(data, strconv.FormatInt(item, 10))
		}
		err = c.client.SRem(c.ctx, key, data...).Err()
	}
	return err
}

// SIntClear 清空指定 key 的 Int64 集合
//   - 如果指定 key 的集合不存或不是一个 Int64 集合, 则返回错误
func (c *RedisCache) SIntClear(key string) error {
	if key == "" {
		return storage.ErrKeyIsEmpty
	}
	kind, err := c.keyKinds.Get(key)
	if err != nil {
		if err == storage.ErrKeyNotExists || err == storage.ErrKeyExpired {
			return storage.ErrKeyNotExists
		}
		return err
	}
	if kind != storage.KindSetInt {
		return storage.ErrValueNotSetInt
	}
	// 单个实例锁, 限制单个实例(主线程)应用内的并发执行
	if c.selfLocked {
		sLock := c.getSelfLock(key)
		sLock.Lock()
		defer sLock.Unlock()
	}

	// 通过 RedisLock 分布式锁限制其他实例线程(客户端)并发执行同一键的重复查询
	rLock := c.redisLock.NewDefault(key)
	if err := rLock.TryLock(); err != nil {
		internal.GetLogger().Error("cache: SIntClear TryLock error", slog.String("key", key), slog.Any("err", err))
		return err
	}
	defer func() {
		if err := rLock.UnlockAndPutPool(); err != nil {
			internal.GetLogger().Error("cache: SIntClear Unlock error", slog.String("key", key), slog.Any("err", err))
		}
	}()

	// 清空集合
	return c.client.Del(c.ctx, key).Err()
}

// SIntContains 判断一个或多个成员是否全部在指定 key 的 Int64 集合中
//   - 如果指定 key 的集合不存或不是一个 Int64 集合, 则返回 false
//   - 查询多个成员, 任意一个成员不在集合中, 则返回 false
func (c *RedisCache) SIntContains(key string, items ...int64) bool {
	if key == "" {
		return false
	}
	if len(items) == 0 {
		return false
	}
	kind, err := c.keyKinds.Get(key)
	if err != nil || kind != storage.KindSetInt {
		return false
	}
	// 单个实例锁, 限制单个实例(主线程)应用内的并发执行
	if c.selfLocked {
		sLock := c.getSelfLock(key)
		sLock.Lock()
		defer sLock.Unlock()
	}

	// 通过 RedisLock 分布式锁限制其他实例线程(客户端)并发执行同一键的重复查询
	rLock := c.redisLock.NewDefault(key)
	if err := rLock.TryLock(); err != nil {
		internal.GetLogger().Error("cache: SIntContains TryLock error", slog.String("key", key), slog.Any("err", err))
		return false
	}
	defer func() {
		if err := rLock.UnlockAndPutPool(); err != nil {
			internal.GetLogger().Error("cache: SIntContains Unlock error", slog.String("key", key), slog.Any("err", err))
		}
	}()

	// 集合存在: 判断一个或多个成员是否在字符串集合中
	if len(items) == 1 {
		return c.client.SIsMember(c.ctx, key, strconv.FormatInt(items[0], 10)).Val()
	}

	// 集合存在: 判断一个或多个成员是否在字符串集合中
	// > 6.2.0 版本后才支持 SMISMEMBER 批量判断成员是否在集合中
	if c.RedisVerGreaterEqual(6, 2) {
		data := make([]any, 0, len(items))
		for _, item := range items {
			data = append(data, strconv.FormatInt(item, 10))
		}
		res := c.client.SMIsMember(c.ctx, key, data...).Val()
		for _, ok := range res {
			// 任意一个成员不在集合中, 则返回 false
			if !ok {
				return false
			}
		}
		return true
	}
	// 低版本不支持批量判断成员是否在集合中, 则逐个查询
	for _, item := range items {
		// 任意一个成员不在集合中, 则返回 false
		if !c.client.SIsMember(c.ctx, key, strconv.FormatInt(item, 10)).Val() {
			return false
		}
	}
	return true
}

// SIntContainsSome 判断一个或多个成员的中任意一个成员是否在指定 key 的 Int64 集合中
//   - 如果指定 key 的集合不存或不是一个 Int64 集合, 则返回 false
//   - 查询多个成员, 任意一个成员存在集合中, 则返回 true
func (c *RedisCache) SIntContainsSome(key string, items ...int64) bool {
	if key == "" {
		return false
	}
	if len(items) == 0 {
		return false
	}
	kind, err := c.keyKinds.Get(key)
	if err != nil || kind != storage.KindSetInt {
		return false
	}

	// 单个实例锁, 限制单个实例(主线程)应用内的并发执行
	if c.selfLocked {
		sLock := c.getSelfLock(key)
		sLock.Lock()
		defer sLock.Unlock()
	}

	// 通过 RedisLock 分布式锁限制其他实例线程(客户端)并发执行同一键的重复查询
	rLock := c.redisLock.NewDefault(key)
	if err := rLock.TryLock(); err != nil {
		internal.GetLogger().Error("cache: SIntContainsSome TryLock error", slog.String("key", key), slog.Any("err", err))
		return false
	}
	defer func() {
		if err := rLock.UnlockAndPutPool(); err != nil {
			internal.GetLogger().Error("cache: SIntContainsSome Unlock error", slog.String("key", key), slog.Any("err", err))
		}
	}()

	// 集合存在: 判断一个或多个成员是否在字符串集合中
	if len(items) == 1 {
		return c.client.SIsMember(c.ctx, key, strconv.FormatInt(items[0], 10)).Val()
	}
	// 集合存在: 判断一个或多个成员是否在字符串集合中
	// > 6.2.0 版本后才支持 SMISMEMBER 批量判断成员是否在集合中
	if c.RedisVerGreaterEqual(6, 2) {
		data := make([]any, 0, len(items))
		for _, item := range items {
			data = append(data, strconv.FormatInt(item, 10))
		}
		res := c.client.SMIsMember(c.ctx, key, data...).Val()
		for _, ok := range res {
			// 任意一个成员存在集合中, 则返回 true
			if ok {
				return true
			}
		}
		return false
	}
	// 低版本不支持批量判断成员是否在集合中, 则逐个查询
	for _, item := range items {
		// 任意一个成员不在集合中, 则返回 false
		if c.client.SIsMember(c.ctx, key, strconv.FormatInt(item, 10)).Val() {
			// 任意一个成员存在集合中, 则返回 true
			return true
		}
	}
	return false
}

// SIntMembers 获取指定 key 的 Int64 集合的所有成员
//   - 如果指定 key 的集合不存或不是一个 Int64 集合, 则返回错误
func (c *RedisCache) SIntMembers(key string) ([]int64, error) {
	if key == "" {
		return []int64{}, storage.ErrKeyIsEmpty
	}
	kind, err := c.keyKinds.Get(key)
	if err != nil {
		if err == storage.ErrKeyNotExists || err == storage.ErrKeyExpired {
			return []int64{}, storage.ErrKeyNotExists
		}
		return []int64{}, err
	}
	if kind != storage.KindSetInt {
		return []int64{}, storage.ErrValueNotSetInt
	}
	// 集合存在: 则返回所有成员
	members, err := c.client.SMembers(c.ctx, key).Result()
	if err != nil {
		return []int64{}, err
	}
	items := make([]int64, len(members))
	for i, v := range members {
		// Redis 集合成员是字符串类型, 这里需要将字符串转换为 Int64 类型
		if items[i], err = strconv.ParseInt(v, 10, 64); err != nil {
			return []int64{}, errors.New("cache: SIntMembers, ParseInt error, key=" + key + ", value=" + v + ", err=" + err.Error())
		}
	}
	return items, nil
}

// SIntTraverse 遍历指定 key 的 Int64 集合的所有成员
//   - 如果指定 key 的集合不存或不是一个 Int64 集合, 则返回错误
//   - fn 签名是 iter.Seq[int64], 迭代过程中, 返回 false 则停止遍历
func (c *RedisCache) SIntTraverse(key string, fn func(int64) bool) error {
	if key == "" {
		return storage.ErrKeyIsEmpty
	}
	kind, err := c.keyKinds.Get(key)
	if err != nil {
		if err == storage.ErrKeyNotExists || err == storage.ErrKeyExpired {
			return storage.ErrKeyNotExists
		}
		return err
	}
	if kind != storage.KindSetInt {
		return storage.ErrValueNotSetInt
	}
	// 注意: 这里不加单实例锁, 因为迭代过程中允许并发操作集合, 比如删除成员等操作
	// 集合存在: 则迭代所有成员
	var (
		cursor  uint64
		members []string
	)
	for {
		members, cursor, err = c.client.SScan(c.ctx, key, cursor, "*", 100).Result()
		if err != nil {
			return err
		}
		for _, item := range members {
			// Redis 集合成员是字符串类型, 这里需要将字符串转换为 Int64 类型
			if i64, err := strconv.ParseInt(item, 10, 64); err != nil {
				return errors.New("cache: SIntMembers, ParseInt error, key=" + key + ", value=" + item + ", err=" + err.Error())
			} else if !fn(i64) {
				return nil
			}
		}
		// 如果游标值为 0，说明迭代结束
		if cursor == 0 {
			return nil
		}
	}
}

// SIntSize 获取指定 key 的 Int64 集合的成员数量
//   - 如果指定 key 的集合不存或不是一个 Int64 集合, 则返回错误
func (c *RedisCache) SIntSize(key string) (int64, error) {
	if key == "" {
		return 0, storage.ErrKeyIsEmpty
	}
	kind, err := c.keyKinds.Get(key)
	if err != nil {
		if err == storage.ErrKeyNotExists || err == storage.ErrKeyExpired {
			return 0, storage.ErrKeyNotExists
		}
		return 0, err
	}
	if kind != storage.KindSetInt {
		return 0, storage.ErrValueNotSetInt
	}
	// 集合存在: 则返回成员数量
	return c.client.SCard(c.ctx, key).Result()
}
